package com.zjpavt.client.hal;

import com.zjpavt.client.enums.ExtendDeviceEnum;
import com.zjpavt.client.extenddevice.lightsensation.ILightSensationDevice;
import com.zjpavt.client.job.JobRunner;
import com.zjpavt.client.util.*;
import io.netty.util.concurrent.DefaultThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 光照强度控制类
 *
 * @author gxy
 */
public class LightIntensityController {
    private static Logger log = LoggerFactory.getLogger(LightIntensityController.class);
    private static final LightIntensityController INSTANCE = new LightIntensityController();

    private static final int LIGHT_THRESHOLD_DEFAULT = 0;
    private static final int LIGHT_LAST_TIME_DEFAULT = 0;
    private static final String LIGHT_DEFAULT_COMMAND = LoopManager.getInstance().getAllClosedCommand();
    private static final int LIGHT_SENSOR_CHECK_INTERVAL_MILLISECONDS = 50 * 1000;
    private long stopLightCommandTime = 0;
    private ScheduledThreadPoolExecutor lightIntensityDetectorThread;
    private final Object threadLock = new Object();
    /**
     * 光控共享数据
     */
    private final LightIntensityBean lightIntensityBean;
    /**
     * LUX group name
     */
    private static final String INI_LUX = "lux";

    private LightIntensityController() {
        lightIntensityBean = new LightIntensityBean();
        initDefaultValue();
        openScheduledDetect();
    }

    public static LightIntensityController getInstance() {
        return INSTANCE;
    }

    private void initDefaultValue() {
        String mLightCommandLastTimeStr;
        String mLightThresholdStr;
        String mLightCommand;
        try {
            mLightCommandLastTimeStr = PropertiesUtil.getPropertiesDefault(Consts.KEY_LIGHT_THRESHOLD_COMMAND_TIME);
            mLightThresholdStr = PropertiesUtil.getPropertiesDefault(Consts.KEY_LIGHT_THRESHOLD);
            mLightCommand = PropertiesUtil.getPropertiesDefault(Consts.KEY_LIGHT_THRESHOLD_COMMAND);
            if (!StringUtil.isNullOrEmpty(mLightCommandLastTimeStr, mLightThresholdStr, mLightCommand)) {
                synchronized (lightIntensityBean) {
                    lightIntensityBean.setLightCommand(mLightCommand);
                    lightIntensityBean.setLightThreshold(Integer.parseInt(mLightThresholdStr));
                    lightIntensityBean.setLightCommandLastTime(Integer.parseInt(mLightCommandLastTimeStr));
                }
            } else {
                lightIntensityBean.setLightCommand(LIGHT_DEFAULT_COMMAND);
            }
        } catch (IOException | NumberFormatException e) {
            log.error(LoggerUtil.convertException2String(e));
        }
    }

    /**
     * 用于开启周期光控检测器
     */
    private void openScheduledDetect() {
        log.debug("lightIntensity detected start");
        synchronized (threadLock) {
            if (lightIntensityDetectorThread == null) {
                lightIntensityDetectorThread = new ScheduledThreadPoolExecutor(1, new DefaultThreadFactory("LightIntensityDetectorThread"));
                lightIntensityDetectorThread.scheduleAtFixedRate(new CheckLightTask(),
                        10, LIGHT_SENSOR_CHECK_INTERVAL_MILLISECONDS, TimeUnit.MILLISECONDS);
            }
        }
    }

    /**
     * 用于关闭周期光控检测器
     */
    private void closeScheduledDetect() {
        log.debug("lightIntensity detected stop");
        synchronized (threadLock) {
            if (lightIntensityDetectorThread != null) {
                lightIntensityDetectorThread.shutdown();
                lightIntensityDetectorThread = null;
            }
        }
    }

    private class CheckLightTask implements Runnable {
        String lightIntensity = null;

        @Override
        public void run() {
            synchronized (lightIntensityBean) {
                log.trace("current lightIntensity:" + lightIntensity + " mLightThreshold:" + lightIntensityBean.getLightThreshold());
                try {
                    //光照阈值或是持续时间 为0 认为光控未开启，关闭
                    if (lightIntensityBean.getLightThreshold() == 0 || lightIntensityBean.getLightCommandLastTime() == 0) {
                        //未开启就关闭光照强度检查
                        closeScheduledDetect();
                        return;
                    }
                    if (StringUtil.isNullOrEmpty(lightIntensity = getFormattedLightIntensity())) {
                        log.debug("not detected lightIntensity ");
                        return;
                    }
                    if (checkLightlntensityDetected()) {
                        JobRunner.getInstance().refreshLightlntensityCommand();
                    }
                } catch (Exception e) {
                    log.error(LoggerUtil.convertException2String(e));
                }
            }
        }
    }

    /**
     * @return 用于外部获取当前光控数据
     */
    public LightIntensityBean getLightIntensityBean() {
        synchronized (lightIntensityBean) {
            return new LightIntensityBean(lightIntensityBean.getLightThreshold(), lightIntensityBean.getLightCommandLastTime(), lightIntensityBean.getLightCommand());
        }
    }

    /**
     * 获取光强
     *
     * @return
     * @throws IOException
     * @throws NumberFormatException
     */
    public int getLightIntensity() throws IOException, NumberFormatException {
        ILightSensationDevice gpsSensor = (ILightSensationDevice) ExtendDeviceManager.getInstance().getExtendDevice(ExtendDeviceEnum.GPS);
        if (gpsSensor != null) {
            return (int)gpsSensor.getLux();
        } else {
            return -1;
        }
    }

    /**
     * @return 获取光强（格式化）
     */
    public String getFormattedLightIntensity() {
        int lightIntensity;
        try {
            lightIntensity = getLightIntensity();
        } catch (IOException | NumberFormatException e) {
            log.warn(e.getMessage());
            return null;
        }
        return String.valueOf(lightIntensity);
    }

    /**
     * 用于保存光照强度指令，并刷新
     *
     * @param lightThreshold 光照阈值
     * @param lightCommand 光照指令
     * @param lightCommandLastTime 持续时间
     */
    public void saveLightIntensity(String lightThreshold, String lightCommand, String lightCommandLastTime) {
        int mLightCommandLastTime;
        int mLightThreshold;
        String mLightCommand;
        try {
            mLightThreshold = Integer.parseInt(lightThreshold);
            mLightCommandLastTime = Integer.parseInt(lightCommandLastTime);
            mLightCommand = lightCommand;

        } catch (NumberFormatException e) {
            log.error(LoggerUtil.convertException2String(e));
            mLightThreshold = LIGHT_THRESHOLD_DEFAULT;
            mLightCommandLastTime = LIGHT_LAST_TIME_DEFAULT;
            mLightCommand = LIGHT_DEFAULT_COMMAND;
        }
        synchronized (lightIntensityBean) {
            lightIntensityBean.setLightCommandLastTime(mLightCommandLastTime);
            lightIntensityBean.setLightThreshold(mLightThreshold);
            lightIntensityBean.setLightCommand(mLightCommand);
            storeLightIntensityProperty();
        }
    }

    /**
     * @return 当前光照强度是否低于阈值
     */
    private boolean checkLightlntensityDetected() {
        if (!ExtendDeviceManager.getInstance().containsExtendDevice(ExtendDeviceEnum.GPS)) {
            return false;
        }
        try {
            int lightIntensity = getLightIntensity();
            return lightIntensity < lightIntensityBean.getLightThreshold();
        } catch (IOException e) {
            log.error(LoggerUtil.convertException2String(e));
            return false;
        }
    }

    /**
     * 用于页面设置不可调整命令
     *
     * @param lightThreshold 光照阈值
     * @param lightCommandLastTime 光照指令
     */
    public void saveLightIntensityNotCommand(String lightThreshold, String lightCommandLastTime) {
        saveLightIntensity(lightThreshold, lightIntensityBean.getLightCommand(), lightCommandLastTime);
    }

    private void storeLightIntensityProperty() {
        try {
            PropertiesUtil.setPropertyOrReplaceDefault(Consts.KEY_LIGHT_THRESHOLD_COMMAND_TIME, String.valueOf(lightIntensityBean.getLightCommandLastTime()));
            PropertiesUtil.setPropertyOrReplaceDefault(Consts.KEY_LIGHT_THRESHOLD_COMMAND, lightIntensityBean.getLightCommand());
            PropertiesUtil.setPropertyOrReplaceDefault(Consts.KEY_LIGHT_THRESHOLD, String.valueOf(lightIntensityBean.getLightThreshold()));
            if (lightIntensityBean.getLightThreshold() != 0 && lightIntensityBean.getLightCommandLastTime() != 0) {
                //当被设置值后去开启周期检测功能
                openScheduledDetect();
                JobRunner jobRunner = JobRunner.getInstance();
                //如果当前正处于光照强度指令,新的值被设置了也需要去重新执行。值有效的情况下，切换
                if (jobRunner.getState() <= JobRunner.EXECUTOR_P_LIGHTINTENSITY_COMMAND_STATE && checkLightlntensityDetected()) {
                    jobRunner.switchToLightlntensityCommand();
                }
            }
        } catch (IOException e) {
            log.error(LoggerUtil.convertException2String(e));
        }
    }

    public long getStopLightCommandTime() {
        return stopLightCommandTime;
    }

    public void setStopLightCommandTime(long stopLightCommandTime) {
        this.stopLightCommandTime = stopLightCommandTime;
    }


    public class LightIntensityBean {
        /**
         * 光照阈值
         */
        private int lightThreshold;
        /**
         * 光照指令持续时间
         */
        private int lightCommandLastTime;
        /**
         * 光照强度指令
         */
        private String lightCommand;

        private LightIntensityBean(int lightThreshold, int lightCommandLastTime, String lightCommand) {
            this.lightThreshold = lightThreshold;
            this.lightCommandLastTime = lightCommandLastTime;
            this.lightCommand = lightCommand;
        }

        private LightIntensityBean() {
        }

        public int getLightThreshold() {
            return lightThreshold;
        }

        public void setLightThreshold(int lightThreshold) {
            this.lightThreshold = lightThreshold;
        }

        public int getLightCommandLastTime() {
            return lightCommandLastTime;
        }

        public void setLightCommandLastTime(int lightCommandLastTime) {
            this.lightCommandLastTime = lightCommandLastTime;
        }

        public String getLightCommand() {
            return lightCommand;
        }

        public void setLightCommand(String mLightCommand) {
            this.lightCommand = mLightCommand;
        }
    }
}
